#include "vanila/baseobject.h"
#include "vanila/dsobject.h"
#include "vanila/object.h"
#include "vanila/virtualmachine.h"
#include "vanila/common.h"
#include "utils/hash.h"
#include "utils/format.h"
#include <iostream>
#include <string>

namespace vanila
{
static VirtualMachine* vm = utils::Singleton<VirtualMachine>::instance();

const char* Object::labels[] = 
{
    "BoundMethod", "Class", "Closure", "Dictionary", "Function", 
    "Instance", "List", "Upvalue", "Native", "String", "Set",
};

const char* Object::label(ObjectType type) noexcept
{
    return Object::labels[ static_cast<int>(type) ];  
}

//! \brief Construct a new Object:: Object object
//! \param[in] type specify Object Type
Object::Object(ObjectType type) : _type{type}, _isMarked{false}
{
    vm->insertObject(this);
}

//! \brief default hash function for object
int64_t Object::hash() const
{
   return reinterpret_cast<int64_t>(this);
}

//! \brief wheather this == that
bool Object::equal(const Object* that) const
{
    return this == that;
}

//! \brief wheather this < that
bool Object::less(const Object* that) const
{
    vm->runtimeError(utils::format("'<' not supported between instances of '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return false;
}

//! \brief wheather this > that
bool Object::greater(const Object* that) const
{
    vm->runtimeError(utils::format("'>' not supported between '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return false;
}

//! \brief add two object
Value Object::add(const Object* that) const
{
    vm->runtimeError(utils::format("'+' not supported between '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return Value{};
}

//! \brief sub two object
Value Object::sub(const Object* that) const
{
    vm->runtimeError(utils::format("'-' not supported between '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return Value{};
}

//! \brief mul two object
Value Object::mul(const Object* that) const
{
    vm->runtimeError(utils::format("'*' not supported between '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return Value{};
}

//! \brief div two object
Value Object::div(const Object* that) const
{
    vm->runtimeError(utils::format("'/' not supported between '%s' and '%s'", 
                                   Object::label(this->_type), Object::label(that->_type)));
    return Value{};
}

}